package graph;


import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import bookworm.AdministratorOfAllBookTagsUsedByTheSystem;

/**
 * This class serves to store starting nodes of the graph and tags/authors related.
 * In our graph, each book review node is associated with another node by an Edge if
 * 1)the review is based on a book by the same author
 * 2)the review is based on a book with the same tag
 * We use this class because when we create a new node to be added to graph, we don't
 * want to have to search in the graph for nodes that must be related to it : the starting
 * node and it's neighbors are the nodes that must be related to the new node. 
 * Also, when we want to visit the graph, we'll have a node from where to start.
 * 
 * @author Mina
 *
 */
public class AdministratorOfAllStartingNodes 
{
	private ConcurrentHashMap<String,BookReviewNode> initialNodesForTags;
	private ConcurrentHashMap<String,BookReviewNode> initialNodesForAuthors;
	private static AdministratorOfAllStartingNodes singletonAdministrator = null;
	/*we use this attribute "singletonAdministrator" because we only need one instance of this 
	  class*/
	
	private AdministratorOfAllStartingNodes()
	{
		initialNodesForTags = new ConcurrentHashMap<String,BookReviewNode>();
		initialNodesForAuthors = new ConcurrentHashMap<String,BookReviewNode>();
	}
	
	public static AdministratorOfAllStartingNodes getAdministratorOfAllStartingNodes()
	{
		if(singletonAdministrator == null)
		{
			singletonAdministrator = new AdministratorOfAllStartingNodes();
		}
		
		return singletonAdministrator;
	}
	
	/**
	 * we'll check for all the tags of the node passed as parameter. If one of these tags
	 * don't already have a starting node, we'll add this node as starting node.
	 * That means a node can be a starting node for many tags.
	 * @param startingNode
	 */
	public synchronized void addNewStartingNodeForTags(BookReviewNode startingNode)
	{
		LinkedList<String> tags = startingNode.getReviewData().getTags();
		for(int i = 0; i < tags.size(); i++)
		{
			String oneTag = tags.get(i);
			if(getStartingNodeForTag(oneTag) == null && 
					AdministratorOfAllBookTagsUsedByTheSystem.isTagUsedByOurSystem(oneTag) == true)
			{
				//if the two conditions are met, then a new starting node is added to hashmap
				if(this.getStartingNodeForTag(oneTag) == null)
				{
					//we'll double check this. You never know.
					this.initialNodesForTags.put(oneTag, startingNode);
				}
			}
		}
	}
	
	public synchronized BookReviewNode getStartingNodeForTag(String tag)
	{
		return initialNodesForTags.get(tag);
	}
	
	/**
	 * it's the same behavior of "addNewStartingNodeForTags", but for authors
	 * @param startingNode
	 */
	public void addNewStartingNodeForAuthors(BookReviewNode startingNode)
	{
		LinkedList<String> authors = startingNode.getReviewData().getAuthors();
		for(int i = 0; i <  authors.size(); i++)
		{
			String oneAuthor =  authors.get(i);
			if(getStartingNodeForAuthor(oneAuthor) == null)
			{
				this.initialNodesForAuthors.put(oneAuthor, startingNode);
			}
		}
	}
	
	public BookReviewNode getStartingNodeForAuthor(String author)
	{
		return initialNodesForAuthors.get(author);
	}
	
	public LinkedList<BookReviewNode> getAllStartingNodesFromAllTags()
	{
		//first we'll get all the tags used by the system
		LinkedList<String> allTags =
				AdministratorOfAllBookTagsUsedByTheSystem.getAllBookTags();
		
		//now, for each tag we'll get the corresponding starting node on the hashMap
		LinkedList<BookReviewNode> startingNodesFromAllTags = new LinkedList<BookReviewNode>();
		for(int i = 0; i < allTags.size(); i++)
		{
			String oneTag = allTags.get(i);
			BookReviewNode startingNodeForOneTag = this.initialNodesForTags.get(oneTag);
			if(startingNodeForOneTag != null)
			{
				//there is a starting node for this tag
				startingNodesFromAllTags.add(startingNodeForOneTag);
			}
			
		}
		return startingNodesFromAllTags;
	}
	
	public LinkedList<String> getAllAuthorsUsedByTheSystem()
	{
		Set<String> setWithAuthors = this.initialNodesForAuthors.keySet();
		Iterator<String> iteratorWithAuthors = setWithAuthors.iterator();
		LinkedList<String> allAuthorsUsedByTheSystem = new LinkedList<String>();
		while(iteratorWithAuthors.hasNext() == true)
		{
			String oneAuthor = iteratorWithAuthors.next();
			allAuthorsUsedByTheSystem.add(oneAuthor);
		}
		
		return allAuthorsUsedByTheSystem;
	}
	
}
